// InstFetch.c
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include "yemu.h"

uint32_t InstFetch(struct ARCHINFO ArchInfo) {
    uint64_t PC = ArchInfo.PC;
    uint32_t i3 = MemRead(ArchInfo, PC + 3);
    uint32_t i2 = MemRead(ArchInfo, PC + 2);
    uint32_t i1 = MemRead(ArchInfo, PC + 1);
    uint32_t i = MemRead(ArchInfo, PC);
    return (i3 << 24) + (i2 << 16) + (i1 << 8) + i;
}

uint8_t MemRead(struct ARCHINFO ArchInfo, uint64_t raddr) {
    assert(ArchInfo.Mem != NULL);
    assert(raddr < MEM_SIZE);
    assert(raddr != 0);
    assert(raddr != UART_TX_ADDR); // UART_TX_ADDR can not be read
    if(raddr == UART_RX_ADDR) {
        char tmp;
        scanf("%c", &tmp);
        return tmp;
    } else if((raddr & ~0x7) == CLOCK_ADDR) {
        return ArchInfo.Mcycle >> 8 * (raddr & 0x7);
    } else {
        return ArchInfo.Mem[raddr];
    }
}

void MemWrite(struct ARCHINFO ArchInfo, uint64_t waddr, uint8_t wdata) {
    assert(ArchInfo.Mem != NULL);
    assert(waddr < MEM_SIZE);
    assert(waddr != 0);
    assert(waddr < MEM_SIZE);
    assert(waddr != UART_RX_ADDR); // UART_RX_ADDR can not be write
    assert(waddr != CLOCK_ADDR);   // CLOCK_ADDR can not be write
    if(waddr == UART_TX_ADDR) {
        printf(COLOR_YELLOW "%c" COLOR_RESET, wdata);
    } else {
        ArchInfo.Mem[waddr] = wdata;
    }
    return ;
}
